#include "ply.h"

ModelPLY::ModelPLY(Stg::World *world, Stg::Pose pose, std::string fname) : Stg::Model(world, NULL, fname)
{
	this->pose = pose;

	Stg::Geom g;
	g.size = Stg::Size(0.1, 0.1, 0.1);				// iRat size
	SetGeom(g);

	faces_tri	 	= NULL;
	vertex_buf	 	= NULL;
	normal_buf 		= NULL;
	colour_buf 		= NULL;

	num_verts 		= 0;
	num_faces		= 0;
	scale = 1.0;
	load_file(fname);
}

ModelPLY::ModelPLY(Stg::Pose pose, std::string fname)
{
	this->pose = pose;

	faces_tri	 	= NULL;
	vertex_buf	 	= NULL;
	normal_buf 		= NULL;
	colour_buf 		= NULL;

	num_verts 		= 0;
	num_faces		= 0;
	scale = 1.0;
	load_file(fname);
}

ModelPLY::~ModelPLY()
{
	if (num_verts != 0)
	{
		delete faces_tri;
		delete vertex_buf;
		delete normal_buf;
		delete colour_buf;
	}
}

/* load model from a file */
void ModelPLY::load_file(std::string fname)
{

	if (num_verts != 0)
	{
		delete faces_tri;
		delete vertex_buf;
		delete normal_buf;
		delete colour_buf;
	}

	num_verts 		= 0;
	num_faces		= 0;

	std::string line;
	std::fstream f(fname.c_str(), std::fstream::in);
	if (!f.is_open())
	{
		std::cerr << "Could not open file: '" << fname << "'\n";
		return;
	}

	// 	check for ply header
	getline(f, line);
	if (line != "ply")
	{
		std::cerr << "File is not ply: '" << fname << "'\n";
		return;
	}

	//	requires ascii format
	do getline(f, line); while (line.find("format") == std::string::npos);
	if (line != "format ascii 1.0")
	{
		std::cerr << "Incorrect ply format in file: " << fname << ". Correct is \"format ascii 1.0\"." << std::endl;
		return;
	}

	//	find number of verts
	do getline(f, line); while (line.find("element vertex") == std::string::npos);
	sscanf(line.c_str(), "element vertex %d", &num_verts);
	if (num_verts == 0)
	{
		std::cerr << "No vertices in file: " << fname << std::endl;
		return;
	}

	//	find number of faces
	do getline(f, line); while (line.find("element face") == std::string::npos);
	sscanf(line.c_str(), "element face %d", &num_faces);
	if (num_faces == 0)
	{
		std::cerr << "No faces in file: " << fname << std::endl;
		return;
	}

	//	skip to end of header
	do getline(f, line); while (line != "end_header");

	//	load in vertex, normal and colour buffers
	vertex_buf = new GLfloat[3*num_verts];
	normal_buf = new GLfloat[3*num_verts];
	colour_buf = new GLubyte[4*num_verts];

	for (unsigned i = 0; i < num_verts; i++)
	{
		getline(f, line);
		float vx, vy, vz;
		float nx, ny, nz;
		unsigned ri, gi, bi, ai;
		sscanf(line.c_str(), "%f %f %f %f %f %f %d %d %d %d", &vx, &vy, &vz, &nx, &ny, &nz, &ri, &gi, &bi, &ai);
		unsigned char r = ri, g = gi, b = bi, a = ai;
		vertex_buf[3*i + 0] = vx;
		vertex_buf[3*i + 1] = vy;
		vertex_buf[3*i + 2] = vz;

		normal_buf[3*i + 0] = nx;
		normal_buf[3*i + 1] = ny;
		normal_buf[3*i + 2] = nz;

		colour_buf[4*i + 0] = r;
		colour_buf[4*i + 1] = g;
		colour_buf[4*i + 2] = b;
		colour_buf[4*i + 3] = a;
	}

	//	load in faces
	faces_tri = new GLuint[3*num_faces];

	for (unsigned i = 0; i < num_faces; i++)
	{
		getline(f, line);
		unsigned v0, v1, v2;
		sscanf(line.c_str(), "3 %d %d %d", &v0, &v1, &v2);
		faces_tri[3*i + 0] = v0;
		faces_tri[3*i + 1] = v1;
		faces_tri[3*i + 2] = v2;
	}

	printf("ModelPLY:%s : loaded %d vertices and %d faces.\n", fname.c_str(), num_verts, num_faces);

	f.close();

	return;
}

/* render model with current camera transformation */
void ModelPLY::DrawBlocks()
{
	std::string visible("visible");
	if (num_faces == 0 || !(int)(GetProperty(visible))) return;

	glEnable(GL_COLOR_MATERIAL);

	glPushMatrix();
	glScalef(scale, scale, scale);

	glVertexPointer(3, GL_FLOAT, 0, vertex_buf);
	glEnableClientState(GL_VERTEX_ARRAY);

	glNormalPointer(GL_FLOAT, 0, normal_buf);
	glEnableClientState(GL_NORMAL_ARRAY);

	glColorPointer(3, GL_UNSIGNED_BYTE, 4, colour_buf);
	glEnableClientState(GL_COLOR_ARRAY);

	glDrawElements(GL_TRIANGLES, 3*num_faces, GL_UNSIGNED_INT, faces_tri);

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);

	glPopMatrix();
}
